package huffman;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;


public class HuffmanIn extends FileInputStream {
	private HuffmanHeader header;
	
	public HuffmanIn(String arg0) throws FileNotFoundException {
		super(arg0);
	}

	public void buildTree() {
		
		int occurance[] = new int[256];
		
		
		
		byte b[] = new byte[1];
		try {
			//Reading the stream
			while(this.available() > 0) {
				read(b);
				occurance[b[0] & 0xFF] ++;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		List<Item> items = new ArrayList<Item>();
		for(int i = 0;i < 256; i++) {
			if(occurance[i] > 0) {
				items.add(new Item(((byte) i) , occurance[i]));
			}
		}
		

		header = new HuffmanHeader(items);

		
	}

	public void compressTo(String name) throws IOException {
		FileOutputStream fos;
		try {
			fos = new FileOutputStream(name);
			buildTree();
			DataOutputStreamEx dos = new DataOutputStreamEx(fos);
			header.write(dos);
			
			
			
			HuffmanIn.this.getChannel().position(0);
			
			byte b[] = new byte[1];
			Item item;
			while(this.available() > 0) {
				read(b);
				item = header.items[b[0] & 0xFF];
				for(int i = 0; i < item.value.length(); i++) {
					dos.writeBit(header.items[b[0] & 0xFF].value.charAt(i) == "1".charAt(0));
				}

			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}




//	public void setValue(Item n, String v) {
//		n.value = v;
//		if(n instanceof Node) {
//			Node no = (Node) n;
//			setValue(no.leftChild, n.value + "0");
//			setValue(no.rightChild,  n.value + "1");
//		} 		
//	}
	public static class Node extends Item  {
		public Node(Byte c, int o) {
			super(c, o);
		}
		public Node(Byte c, int o, Item l, Item r) {
			this(c, o);
			leftChild = l;
			rightChild = r;
		}
		public Item leftChild = null;
		public Item rightChild = null;
				
		

		
	}
	
	public static class Item  implements Comparable<Item>, Comparator<Item> {
		@Override
		public boolean equals(Object obj) {
			Item i = (Item) obj;
			return (character == i.character);
		}
		public Byte character = 0;
		public Integer occurance = 0;
		public String value = "";
		public Item(Byte c, int o) {
			character = c;
			occurance = o;
		}
		@Override
		public int compareTo(Item i) {
			int v = occurance-i.occurance;
			if(v == 0 && i.character != null && character != null) {
				return character - i.character;
			}
			return v;
		}
		@Override
		public int compare(Item i1, Item i2) {
			int v = i1.occurance-i2.occurance;
			if(v == 0 && i1.character != null && i2.character != null) {
				return i1.character - i2.character;
			}
			return v;
		}
		
		public boolean[] getBooleanArray() {
			boolean b[] = new boolean[value.length()];
			for(int i = 0;i < value.length(); i++) {
				b[i] = value.charAt(i) == "1".charAt(0);
			}
			return b;
		}
			
	}
	
}
